package datastructures.stack;

import java.math.BigDecimal;

/**
 * 使用栈实现综合计算器 + - * /
 *
 * @author hck
 */
public class TestStackCalculator {
    public static void main(String[] args) {
        String calculateStr = "10*3-19+6*3/2+5";
        LinkedStack<BigDecimal> numberStack = new LinkedStack<>();
        LinkedStack<String> operatorStack = new LinkedStack<>();
        for (int i = 0; i < calculateStr.length(); i++) {
            char currentChar = calculateStr.charAt(i);
            //  如果是数字
            if (Character.isDigit(currentChar)) {
                StringBuilder tempDigit = new StringBuilder(String.valueOf(currentChar));
                //  取到最后非数字位
                for (int j = i + 1; j < calculateStr.length(); j++) {
                    if (Character.isDigit(calculateStr.charAt(j))) {
                        tempDigit.append(calculateStr.charAt(j));
                        i++;
                    } else {
                        break;
                    }
                }
                //  入数字栈
                numberStack.push(new BigDecimal(tempDigit.toString()));
            } else {
                if (operatorStack.isEmpty()) {
                    //  如果操作栈为空则直接入栈
                    operatorStack.push(String.valueOf(currentChar));
                    continue;
                }
                //  比较当前操作符和栈顶操作符
                String stackTopOperator = operatorStack.peek();
                int currentLevel = getOperatorLevel(String.valueOf(currentChar));
                int stackTopLevel = getOperatorLevel(stackTopOperator);
                if (currentLevel <= stackTopLevel) {
                    //  如果当前操作符优先级小于栈顶操作符,则先弹出高优先级操作符进行计算
                    BigDecimal b = numberStack.pop();
                    BigDecimal a = numberStack.pop();
                    BigDecimal c = calculator(a, b , operatorStack.pop());
                    numberStack.push(c);
                    //  然后将当前操作符入栈
                    operatorStack.push(String.valueOf(currentChar));
                } else {
                    //  直接入栈
                    operatorStack.push(String.valueOf(currentChar));
                }
            }
        }

        if (!operatorStack.isEmpty()) {
            while (!operatorStack.isEmpty()) {
                String operate = operatorStack.pop();
                BigDecimal b = numberStack.pop();
                BigDecimal a = numberStack.pop();
                BigDecimal c = calculator(a, b , operate);
                numberStack.push(c);
            }
        }
        System.out.println(numberStack.pop());
    }


    /**
     * 计算
     *
     * @param a
     * @param b
     * @param operate
     * @return
     */
    private static BigDecimal calculator(BigDecimal a, BigDecimal b, String operate) {
        switch (operate) {
            case "*":
                return a.multiply(b);
            case "/":
                return a.divide(b, 2);
            case "+":
                return a.add(b);
            case "-":
                return a.subtract(b);
            default:
                throw new IllegalArgumentException("illegal operator:" + operate);
        }
    }

    /**
     * 获取操作符优先级
     *
     * @param operator
     * @return
     */
    private static int getOperatorLevel(String operator) {
        if ("*".equals(operator) || "/".equals(operator)) {
            return 1;
        } else if ("+".equals(operator) || "-".equals(operator)) {
            return 0;
        } else {
            return -1;
        }
    }
}
